﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text; 
using MyBasicLib.Reflection;
using MyBasicLib.Data.ORMLiteV2;

namespace MyBasicLib.Data.ORMLiteNew.SqlClient
{
    public class SelectClause
    {
        public string AliName;
        public string SourceName;
    }

    /// <summary>
    /// 处理SelectDbExpression, 
    /// </summary>
    /// <remarks>
    /// p=>p
    /// p=>p.t
    /// p=>p.Id
    /// p=>new {Id=...}
    /// p=>new App{Id=...}
    /// </remarks>
    public class SelectTranslator : ExpressionTranslator
    {
        public List<SelectClause> SelectClauses = new List<SelectClause>();

        private void GetSelectClausesForType(Type type, string tableAli)
        {
            SelectClauses.AddRange(TypeDataCache.GetTypeData(type).GetPropertyInfos().Select(
                p => new SelectClause
                         {
                             SourceName = string.Format("[{1}].[{0}]", p.Key, tableAli),
                             AliName = string.Format("[{0}]", p.Key)
                         }
                                       ));
        }


        //处理没有select语句的情况
        public override void Translate(Expression selectExp, StringBuilder sb, int parameterCount,
                                       TableNameAliasCache tableAliasCache, IMappingProvider mappingProvider)
        {
            if (selectExp == null) return;

            Expression exp = selectExp; // selectExp.Selector;
            if (exp.NodeType == ExpressionType.Constant)
            {
                var type = (exp as ConstantExpression).Value as Type;
                if (mappingProvider.IsValidTableClass(type))
                {
                    string ali = "t0";
                    GetSelectClausesForType(type, ali);
                    return;
                }
            }
            base.Translate(exp, sb, parameterCount, tableAliasCache, mappingProvider);
        }
        //p=>p
        //p=>p.t
        //p=>p.Id
        protected override Expression VisitLambda<T>(Expression<T> node)
        {

            var lambda = node as LambdaExpression;
            if (lambda.Body is MemberExpression || lambda.Body is ParameterExpression)
            {
                Type type = lambda.Body.Type;
                if (TableNameAliasCache.MappingProvider.IsValidTableClass(type)) //p=>p,p=>p.t
                {
                    string ali = TableAliasCache.GetTableAlias(lambda);
                    GetSelectClausesForType(type, ali);
                    return lambda;
                }
                else
                {
                    //p=>p.Id
                    string str = GetExpressionString(() => Visit(lambda.Body));
                    string nm = (lambda.Body as MemberExpression).Member.Name;
                    var sc = new SelectClause
                                 {
                                     SourceName = str,
                                     AliName = string.Format("[{0}]", nm)
                                 };
                    SelectClauses.Add(sc);
                }
            }
            return base.VisitLambda(node);
        }

        //{new App() {Id = p.Id}} 
        protected override Expression VisitMemberInit(MemberInitExpression node)
        {
            for (int i = 0; i < node.Bindings.Count; i++)
            {
                string nm = node.Bindings[i].Member.Name;
                string str = GetExpressionString(() => VisitMemberBinding(node.Bindings[i]));

                var sc = new SelectClause
                             {
                                 SourceName = str,
                                 AliName = string.Format("[{0}]", nm)
                             };
                SelectClauses.Add(sc);
            }
            return node;
        }

        //{new  {Id = p.Id}} 
        protected override Expression VisitNew(NewExpression node)
        {
            ReadOnlyCollection<Expression> original = node.Arguments;
            int n = original.Count;
            if (n == 0) throw new NotSupportedException("请在select语句中使用类似p=>p而不是p=>new App()的语法");
            for (int i = 0; i < n; i++)
            {
                string str = GetExpressionString(() => Visit(original[i]));
                string nm = node.Members[i].Name;
                var sc = new SelectClause
                             {
                                 SourceName = str,
                                 AliName = string.Format("[{0}]", nm)
                             };
                SelectClauses.Add(sc);
            }
            return node;
        }

        protected override Expression VisitMethodCall(MethodCallExpression m)
        {
            throw new NotSupportedException("未能将方法" + m.Method + "转换为Sql语句。");
        }
    }
}